package com.xw.Mail.Parser;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.activation.DataSource;
import javax.mail.Address;
import javax.mail.Flags;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.internet.MimeMessage;
import org.apache.commons.io.IOUtils;
import org.apache.commons.mail.util.MimeMessageParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.xw.Beans.SaveMail;
import com.xw.Beans.SaveMailAttachment;
import com.xw.Enums.MailEnums;
import com.xw.Service.MailService;
import com.xw.Utils.StrUtil;

/**
 * 邮件解析类
 * @author YangJianQuan
 * 
 */
@Component
public class MessageParser {
	Logger logger = LoggerFactory.getLogger(MessageParser.class);
	@Autowired
	private MailService mailService;
	@Autowired
	private HtmlParse htmlImageParse;
	
	//上传文件的根目录
	@Value("${upload.file.rootPath}")
	private String uploadRootPath;
	//上传文件的文件夹名
	@Value("${upload.file.rootFolderName}")
	private String uploadRootFolderName;
	
	//附件文件夹名称，修改之后注意修改SpringMvc静态资源配置
	public static final String folderName = "mailAttachments";
	
	
	/**
	 * 解析邮件
	 * @param message 邮件对象
	 */
	private void parse(Message message) {
		try {
			Flags flags = message.getFlags();
			//邮箱名
			String mailName = message.getFolder().getStore().getURLName().getUsername();		
			if (flags.contains(Flags.Flag.SEEN)){
				logger.info("这是一封已读邮件,跳过...");
				return;
			}
			MimeMessage mimeMessage = (MimeMessage) message;
			String messageId = mimeMessage.getMessageID();
			//获取References
			String[] references = mimeMessage.getHeader("References");
			//回复邮件的第一封邮件的id
			String firstReferenceId = "";
			StringBuffer mailReference = new StringBuffer();
			if (null!=references && references.length>0) {
				for (String string : references) {
					mailReference.append(string);
				}
				List<String> referencesList = getReferencesList(mailReference.toString());
				if (!referencesList.isEmpty()) {
					firstReferenceId = referencesList.get(0);
					logger.info("邮件root_Mail_id ="+firstReferenceId);
				}
				logger.info("邮件的references："+mailReference);
			}
			MimeMessageParser parser = new MimeMessageParser(mimeMessage).parse();
			String from = parser.getFrom(); // 获取发件人地址
			//String replyTo = parser.getReplyTo();// 获取回复邮件时的收件人
			String subject = parser.getSubject(); // 获取邮件主题
			String htmlContent = parser.getHtmlContent(); // 获取Html内容
			String plainContent = parser.getPlainContent(); // 获取纯文本邮件内容（注：有些邮件不支持html）
			//获取收件人地址
			Address[] toAddress = message.getRecipients(RecipientType.TO);
			String toAddressStr = getAddressStr(toAddress);
			//抄送人地址
			Address[] ccAddress = message.getRecipients(RecipientType.CC);
			String ccAddressStr = getAddressStr(ccAddress);
			//组装邮件实体
			SaveMail mail = new SaveMail();
			mail.setFromUser(from);
			mail.setCcUser(ccAddressStr);
			mail.setToUser(toAddressStr);
			mail.setMailBox(mailName);
			mail.setReceiveTime(message.getReceivedDate());
			mail.setContent(plainContent);
			mail.setTitle(subject);
			mail.setContentType(htmlContent==null?MailEnums.MAIL_CONTENT_TYPE_TEXT:MailEnums.MAIL_CONTENT_TYPE_HTML);
			mail.setMailType(MailEnums.MAIL_TYPE_RECEIVE);
			mail.setMessageId(messageId);
			mail.setReferences(mailReference.toString());
			mail.setRootMessageId(firstReferenceId);
			//解析邮件html img标签，并替换图片url为本地的url
			String parseredHtml = htmlImageParse.parse(htmlContent,from,parser);
			mail.setHtmlContent(parseredHtml);
			// 获取附件，并写入磁盘
			String attaIds = saveAttachmentToDisk(mailName, parser, mail);
			mail.setAttachmentIds(attaIds);
			//邮件写库
			mailService.saveMail(mail);
			//加入待通知队列
			logger.info("解析邮件<"+mail.getTitle()+">完成,加入通知队列：");
		} catch (Exception e) {
			logger.error("解析邮件发生异常：",e);
		}
	}
	
	/**
	 * 描述：获取邮件关联id串
	 * @author 杨建全
	 * @date 2017年11月17日
	 * @param string
	 * @return
	 */
	private static List<String> getReferencesList(String references) {
		List<String> referencesList = new ArrayList<>();
		Pattern p = Pattern.compile("<(.*?)>");
		Matcher m = p.matcher(references);
		while (m.find()) {
			referencesList.add(m.group(0));
			//referencesList.add(m.group(1));		//不包含“<>”
		}
		return referencesList;
	}
	
	/**
	 * 将附件保存到磁盘，并返回附件对象
	 * @param mailName	邮箱名
	 * @param parser	邮件解析对象
	 * @param mail	邮件实体对象
	 */
	private String saveAttachmentToDisk(String mailName, MimeMessageParser parser, SaveMail mail) {
		String ret = "";
		//邮件附件存放位置
		String path = uploadRootPath+File.separator+uploadRootFolderName+File.separator+folderName;
		List<DataSource> attachments = parser.getAttachmentList(); 
		List<SaveMailAttachment> mailAttachmentsList = new ArrayList<>();
		//遍历附件
		for (DataSource ds : attachments) {
			//获取邮箱名，用于存储文件
			String generateFileName = StrUtil.uuidWithodHyphen();
			String fileFolderName = path + File.separator +mailName;
			OutputStream outStream = null;
			try {
				File folder = new File(fileFolderName);
				if (!folder.exists()) {
					folder.mkdirs();
				}
				String dsName = ds.getName();
				String fileName = "";
				if (dsName.contains("/")) {
					fileName = fileFolderName+File.separator+generateFileName+"." +StrUtil.getFileType(dsName);
				}else{
					fileName = fileFolderName+File.separator+generateFileName+"_"+ds.getName();
				}
				outStream = new FileOutputStream(fileName);
				int size = IOUtils.copy(ds.getInputStream(), outStream);
				logger.info("附件:" + fileName);
				//组装邮件附件类
				String attaId = mailService.getAttachmentId();
				ret = ret+attaId+",";
				SaveMailAttachment mailAttachment = new SaveMailAttachment();
				mailAttachment.setId(attaId);
				mailAttachment.setName(ds.getName());
				mailAttachment.setUploadTime(new Date());
				mailAttachment.setUrl(uploadRootFolderName+"/"+folderName+"/"+mailName+"/"+generateFileName+"_"+ds.getName());
				mailAttachment.setSize(size/1024+"k");
				//加入集合
				mailAttachmentsList.add(mailAttachment);
			} catch (FileNotFoundException e) {
				logger.error("创建文件失败！",e);
			} catch (IOException e) {
				logger.error("下载附件失败！", e);
			} finally {
				if (outStream != null) {
					try {
						outStream.close();
					} catch (IOException e) {
						logger.error("",e);
					}
				}
			}
		}
		mailService.saveAttachments(mailAttachmentsList);
		//返回id串
		int end = ret.length()-1;
		if (end>0) {
			return ret.substring(0,end);
		}
		return "";
	}
	/**
	 * 获取地址字符串
	 * @param ccAddress
	 * @return
	 */
	private String getAddressStr(Address[] Address) {
		StringBuilder addressStr =new StringBuilder("");
		if (null!= Address) {
			for (Address address : Address) {
				String addstr = StrUtil.getByLessThan(address.toString());
				addressStr.append(addstr+",");
			}
		}
		if (addressStr.length()<1) {
			addressStr.append(",");
		}
		return addressStr.substring(0, addressStr.length()-1);
	}

	public void parse(Message... messages) {
		if (messages == null || messages.length == 0) {
			logger.info("没有任何邮件");
		} else {
			for (Message m : messages) {
				if (null!=m) {
					parse(m);
				}
			}
			// 最后关闭连接
/*			if (messages[0] != null) {
				Folder folder = messages[0].getFolder();
				if (folder != null) {
					try {
						//Store store = folder.getStore();
						folder.close(true);// 参数false表示对邮件的修改不传送到服务器上
						logger.info("邮件解析完成...");
						if (store != null) {
							store.close();
						}
					} catch (MessagingException e) {
						// ignore
					}
				}
			}*/
		}
	}
}
